<?php
/*
Auth:Sang
Desc:HTTP头解析类
Date:2014-11-01
*/
namespace Lib;
class Parser{
    private $error=0,
            $isFinished=0,
            $header=[];
    const HTTP_EOF="\r\n\r\n";
    //http头最大长度不得超过2k
    const HTTP_HEAD_MAXLEN = 2048; 

    public function __construct(){
        $_GET = $_POST = $_COOKIE = $_FILES = $_REQUEST = [];
        $GLOBALS['rawContent'] = '';
        $_SERVER = [
            'DOCUMENT_ROOT' => $_SERVER['DOCUMENT_ROOT'],
            'REQUEST_TIME_FLOAT' => microtime(true),
            'REQUEST_TIME' => time(),
        ];
    }

    public function execute(&$buffer){
        if(empty($this->header)){
            if(strpos($buffer,self::HTTP_EOF)===false)
                return;
            list($header,$_) = explode(self::HTTP_EOF,$buffer,2);
            if(strlen($header) > self::HTTP_HEAD_MAXLEN){
                $this->error = 'The request header limit exceeded';
                return false;
            }
            //解析header
            $this->header = $this->parseHeader($header);
            unset($header,$_);
        }
        if(!empty($this->header)){
            //如果是post，则解析post
            if($this->header['method']=='POST'){
                list($_,$body) = explode(self::HTTP_EOF,$buffer,2);
                if($this->parsePost($body)==false){
                    return;
                }
            }

            //解析Cookies
            if (!empty($this->header['Cookie']))
            {
                self::parseCookie($this->header);
            }

            foreach($this->header as $key=>$val){
                $_SERVER['HTTP_'.strtoupper(str_replace('-','_',$key))] = $val;
            }

            $_REQUEST = array_merge($_GET,$_POST);

            $this->isFinished++;
            return true;
            
        }
    }

    static function parseCookie($header){
        $_COOKIE = self::parseParams($header['Cookie']);
    }

    public function hasError(){
        return !empty($this->error);
    }
    public function getError(){
        return $this->error;
    }

    public function isFinished(){
        return $this->isFinished>0;
    }

    private function parseHeader($header){
        $header = explode("\r\n",$header);

        $meta = [];
        // HTTP协议头,方法，路径，协议[RFC-2616 5.1]
        list($meta['method'], $meta['uri'], $meta['protocol']) = explode(' ', $header[0], 3);
        //错误的HTTP请求
        if (empty($meta['method']) or empty($meta['uri']) or empty($meta['protocol']) or !in_array($meta['method'],array('GET','POST','DELETE','PUT'))){
            $this->error = '非法请求!';
            return false;
        }
        unset($header[0]);
        $meta['uri'] = preg_replace('/\/{2,}/','/',$meta['uri']);
        $url_info = parse_url($meta['uri']);
        $_SERVER['REQUEST_URI'] = $meta['uri'];
        $_SERVER['PATH_INFO'] = $url_info['path'];
        $_SERVER['PHP_SELF'] = explode('?',$meta['uri'],2)[0];
        $_SERVER['SCRIPT_NAME'] = $url_info['path'];
        $_SERVER['SCRIPT_FILENAME'] = rtrim(APP_PATH,'/').$url_info['path'];
        if (isset($url_info['fragment'])) $_SERVER['FRAGMENT'] = $url_info['fragment'];
        if (isset($url_info['query']))
        {
            $_SERVER['QUERY_STRING'] = $url_info['query'];
            parse_str($url_info['query'],$_GET);
        }
        
        $headers = [];
        foreach($header as $line){
            list($key,$val) = explode(':',$line,2);
            $headers[$key] = trim($val,"\r\n \t\"");
        }
        $headers['method'] = $meta['method'];
        unset($meta);
        return $headers;
    }

    private function parsePost($body){
        if(isset($this->header['Content-Length'])){
            if($this->header['Content-Length']>strlen($body))
                return false;
            //分三种情况 1带name字段的文件上传 2普通POST 3不带字段的数据上传
            if(isset($this->header['Content-Type']) && $cd = strstr($this->header['Content-Type'], 'boundary')){
                $this->parseFormData($body,$cd);
            }elseif(parse_str($body, $_POST) && !empty($_POST)){
                
            }elseif(!empty($body)){
                // $_FILES['file'] = array(
                //     'name' => 'upload.file',
                //     'type' => $this->header['Content-Type'],
                //     'size' => $this->header['Content-Length'],
                //     'error' => UPLOAD_ERR_OK,
                //     'source' => $body
                // );
                $GLOBALS['rawContent'] = $body;
            }else{
                $_POST = [];
            }
            $this->isFinished++;
            return true;
        }else{
            $this->error = '非法请求:content-length不能为空';
            return false;
        }
    }

    private function parseFormData($body,$cd){
        $cd = '--' . str_replace('boundary=', '', $cd);
        $form = explode($cd, rtrim($body, "-")); //去掉末尾的--
        $str = '';
        $file_str = '';
        foreach ($form as $f)
        {
            if ($f === '') continue;
            $parts = explode("\r\n\r\n", trim($f));
            $head = self::parseHeaderLine($parts[0]);
            if (!isset($head['Content-Disposition'])) continue;
            $meta = self::parseParams($head['Content-Disposition']);
            //filename字段表示它是一个文件
            if (!isset($meta['filename']))
            {
                if(count($parts) < 2) $parts[1] = "";
                $str .= $meta['name'] .'='. urlencode(trim($parts[1], "\r\n")).'&';
            }
            else
            {
                if(isset($parts[1])){
                    $file = trim($parts[1]);
                    $tmp_file = tempnam('/tmp', 'sw_tmp_');
                    file_put_contents($tmp_file, $file);
                    if (!isset($meta['name'])) $meta['name'] = 'file';
                    $file_str .= $meta['name'].'[name]='.$meta['filename'].
                                '&'.$meta['name'].'[type]='.$head['Content-Type'].
                                '&'.$meta['name'].'[size]='.strlen($file).
                                '&'.$meta['name'].'[error]='.UPLOAD_ERR_OK.
                                '&'.$meta['name'].'[tmp_name]='.$tmp_file.'&';
                    unset($file);
                }
            }
        }
        if(!empty($str)){
            parse_str($str,$_POST);
            unset($str);
        }
        if(!empty($file_str)){
            parse_str($file_str,$_FILES);
            unset($file_str);
        }
    }

    static function parseHeaderLine($headerLines){
        if (is_string($headerLines))
        {
            $headerLines = explode("\r\n", $headerLines);
        }
        $header = array();
        foreach ($headerLines as $_h)
        {
            $_h = trim($_h);
            if (empty($_h)) continue;
            $_r = explode(':', $_h, 2);
            $key = $_r[0];
            $value = isset($_r[1])?$_r[1]:'';
            $header[trim($key)] = trim($value);
        }
        return $header;
    }

    static function parseParams($str){
        $params = array();
        $blocks = explode(";", $str);
        foreach ($blocks as $b)
        {
            $_r = explode("=", $b, 2);
            if(count($_r)==2)
            {
                list ($key, $value) = $_r;
                $params[trim($key)] = trim($value, "\r\n \t\"");
            }
            else
            {
                $params[$_r[0]] = '';
            }
        }
        return $params;
    }
}